#include <iostream>
#include <memory>
#include <thread>
#include "TcpServer.hpp"
#include "Epoller.hpp"
#include "Socket.hpp"
#include "LogMessage.hpp"
#include "Accept.hpp"

// 在epoll模型的ET工作模式下，每一个套接字都要有独立的
// 发送和接受缓冲区

using handler_t = std::function<void()>;

const int defaultport = 8080;
const int defaultthread = 5;

void ThreadInit(int thread_id)
{
    lg.LogMessage(Debug, "%d thread create success", std::this_thread::get_id());

    // 1.创建listen套接字并设置为非阻塞
    SetNonBlocking(thread_id);

    // 2.创建Epoll模型
    Epoller *epoll = new (Epoller);

    // 3.将listensock添加到Epoll模型当中
    epoll->AddEpoll(thread_id, EPOLLIN | EPOLLET);

    // 4.创建TCP服务器对象
    TcpServer *ptr = new TcpServer(thread_id, epoll);
    Accepter *accepter = new Accepter;

    // 5.创建listen的Connect对象
    Connect *listenconnect = new Connect(thread_id, ptr);
    auto acceptconnect = std::bind(&Accepter::AcceptSock, accepter, epoll, ptr);
    listenconnect->Establishment(acceptconnect, nullptr, nullptr);

    // 6.将Connect对象添加进Tcp服务器中
    ptr->AddConnection(thread_id, listenconnect);

    // 7.启动服务器
    ptr->Loop();

    // n.内存释放
    delete epoll;
    delete accepter;
    // 所有Connect对象以及sockfd都交给TCP对象去释放
    delete ptr;
}

// 文件描述符分配：
// 0 1 2 为默认打开的三个，标准输入，标准输出，标准错误
// 3 为主线程的listen socket
// 4 为主线程的epoll模型的fd
// 5 6 7 8 9为主线程创建的5个管道文件，也是未来从线程的读取fd
// 10 11 12 13 14 15为从线程创建的epoll模型的fd

int main()
{
    // 1.创建listen套接字并设置为非阻塞
    Socket *listensock = new (TcpSocket);
    listensock->CreateBindListenSocket(defaultport);
    SetNonBlocking(listensock->GetSockfd());

    // 2.创建Epoll模型
    Epoller *epoll = new (Epoller);

    // 3.将listensock添加到Epoll模型当中
    epoll->AddEpoll(listensock->GetSockfd(), EPOLLIN | EPOLLET);

    // 4.创建TCP服务器对象
    TcpServer *ptr = new TcpServer(listensock, epoll, defaultthread);
    Accepter *accepter = new Accepter;

    // 5.创建多线程，并且保证每个线程的读取fd都对应一个管道文件
    std::vector<std::thread> threads;
    threads.resize(defaultthread);
    for (int i = 0; i < defaultthread; i++)
    {
        threads.push_back(std::thread(ThreadInit, i + 5));
    }
    // 5.创建listen的Connect对象
    Connect *listenconnect = new Connect(listensock, ptr);
    auto acceptconnect = std::bind(&Accepter::ListenAccepter, accepter, listensock, ptr);
    listenconnect->Establishment(acceptconnect, nullptr, nullptr);

    // 6.将Connect对象添加进Tcp服务器中
    ptr->AddConnection(listensock->GetSockfd(), listenconnect);

    // 7.启动服务器
    ptr->Loop();

    // n.内存释放
    close(listensock->GetSockfd());
    delete listensock;
    delete epoll;
    delete accepter;
    // 所有Connect对象以及sockfd都交给TCP对象去释放
    delete ptr;

    return 0;
}